﻿using Consul;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace RWProxyDemo.Utils
{
    /// <summary>
    /// ConsulHelper
    /// </summary>
    public static class ConsulHelper
    {
        static IConfiguration config = null;
        //static IConfiguration config = new ConfigurationBuilder()
        //.AddInMemoryCollection() //将配置文件的数据加载到内存中
        //.SetBasePath(Directory.GetCurrentDirectory()) //指定配置文件所在的目录
        //.AddJsonFile(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development" ? "appsettings.Development.json" : "appsettings.json", optional: true, reloadOnChange: true) //指定加载的配置文件  --划重点..记得始终复制
        //.Build(); //编译成对象

        /// <summary>
        /// 地址
        /// </summary>
        static Dictionary<string, List<string>> Urls = new Dictionary<string, List<string>>();

        /// <summary>
        /// 获取服务地址
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static string GetServiceUrl(string name)
        {
            if (!Urls.ContainsKey(name))
                return GetServiceUrl_Consul(name);

            List<string> urls = Urls[name];
            var index = new Random().Next(urls.Count());
            var url = urls.ElementAt(index);
            return url;
        }

        /// <summary>
        /// 获取Consul地址
        /// 直接从Consul中获取，不建议使用这个，因为加载需要时间
        /// </summary>
        /// <returns></returns>
        public static string GetServiceUrl_Consul(string name)
        {
            string url = "";
            using (var consul = new ConsulClient(c =>
            {
                string url = config["ConsulService:ConsulAddress"];
                c.Address = new Uri(url);
            }))
            {
                //指定取在Consul注册的某个服务的所有节点
                //var services = consul.Agent.Services().Result.Response.Values.Where(p => p.Service.Equals(name, StringComparison.OrdinalIgnoreCase));
                //指定取在Consul注册的某个服务的健康节点
                var services = consul.Health.Service(name, "", true).Result.Response.Select(x => x.Service).ToList();
                //客户端负载均衡，随机选出一台服务
                if (services.Count() == 0)
                {
                    return url;
                }
                var index = new Random().Next(services.Count());
                var singleService = services.ElementAt(index);
                Console.WriteLine($"Index={index},ID={singleService.ID},Service={singleService.Service},Addr={singleService.Address},Port={singleService.Port}");
                url = $"http://{singleService.Address}:{singleService.Port}/";
            }
            return url;
        }

        /// <summary>
        /// 是否继续
        /// </summary>
        static bool isContinue = true;

        /// <summary>
        /// 启动获取Consul里面注入的服务地址
        /// </summary>
        public static void Start(IConfiguration configuration)
        {
            config = configuration;
            //配置文件中InvokeService，配置了所有需要从Consul中获取的地址
            string servicesStr = config["InvokeService"];
            string[] services = servicesStr.Split(',');
            Task.Run(() =>
            {
                while (isContinue)
                {
                    try
                    {
                        using (var consul = new ConsulClient(c =>
                        {
                            c.Address = new Uri(config["ConsulService:ConsulAddress"]);
                        }))
                        {
                            Dictionary<string, List<string>> currentUrls = new Dictionary<string, List<string>>();
                            foreach (string server in services)
                            {
                                if (string.IsNullOrWhiteSpace(server)) continue;
                                //指定取在Consul注册的某个服务的所有节点
                                //var agentServices = consul.Agent.Services().Result.Response.Values.Where(p => p.Service.Equals(server, StringComparison.OrdinalIgnoreCase));
                                //指定取在Consul注册的某个服务的健康节点
                                var agentServices = consul.Health.Service(server, "", true).Result.Response.Select(x => x.Service).ToList();
                                //客户端负载均衡，随机选出一台服务
                                if (agentServices.Count() == 0)
                                    continue;

                                List<string> serverUrl = new List<string>();
                                foreach (AgentService agentService in agentServices)
                                {
                                    string url = $"http://{agentService.Address}:{agentService.Port}/";
                                    if (!serverUrl.Contains(url))
                                        serverUrl.Add(url);
                                }
                                currentUrls.Add(server, serverUrl);
                            }
                            Urls = currentUrls;
                        }
                        Thread.Sleep(2000);
                    }
                    catch
                    {
                    }
                }
            });
        }
    }
}
